﻿using System;
using System.Collections.Generic;

namespace CoreEx.MicroMapper
{   
    /// <summary>
    /// Represents a generic object mapper that is capable of mapping 
    /// the values from one object instance to another.
    /// </summary>
    /// <typeparam name="TSource">The type of object to map from.</typeparam>
    /// <typeparam name="TTarget">The type of object to map to.</typeparam>
    public interface IMicroMapper<TSource, TTarget> 
    {
        /// <summary>
        /// Applies the mapping transformation to the <typeparamref name="TTarget"/> instance.
        /// </summary>
        /// <param name="source">An instance of <typeparamref name="TSource"/>  to map from.</param>
        /// <returns>A new instance of <typeparamref name="TTarget"/>  containing the result of the mapping.</returns>
        TTarget Apply(TSource source);
        
        /// <summary>
        /// Applies the mapping transformation to an <see cref="IEnumerable{T}"/>.
        /// </summary>
        /// <param name="sourceList">An <see cref="IEnumerable{T}"/> containing<typeparamref name="TSource"/> instances</param>
        /// <returns></returns>
        IEnumerable<TTarget> Apply(IEnumerable<TSource> sourceList);
        
        /// <summary>
        /// A function used to retrieve the value from the <typeparamref name="TSource"/> instance.
        /// </summary>                
        Func<IAccessorInfo, TSource, object> SourceAccessor { get; set; }
                
        /// <summary>
        /// An action delegate used to set the value on the <typeparamref name="TTarget"/> instance.
        /// </summary>
        Action<IAccessorInfo, TTarget , object> TargetAccessor { get; set; }
        
        /// <summary>
        /// A function delegate that is responsible for creating new <typeparamref name="TTarget"/> instances.
        /// </summary>
        Func<TSource,TTarget> TargetFactory { get; set; }
        
        /// <summary>
        /// Adds an exlicit mapping to the <see cref="IMicroMapper{TSource,TTarget}"/>.
        /// </summary>
        /// <param name="mapping">An action delegate that represents the custom mapping.</param>
        /// <returns></returns>
        IMicroMapper<TSource, TTarget> Explicit(Action<TSource, TTarget> mapping);
              
        /// <summary>
        /// Gets or sets the <see cref="Func{TResult}"/> used to retrieve the properties of <typeparamref name="TSource"/> .
        /// </summary>
        Func<TSource,IEnumerable<IAccessorInfo>> SourceAccessorSelector { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="Func{TResult}"/> used to retrive the properties of <typeparamref name="TTarget"/> .
        /// </summary>
        Func<TTarget,IEnumerable<IAccessorInfo>> TargetAccessorSelector { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="IAccessorInfoMatcher"/> that is 
        /// responsible for finding matching accessors between <typeparamref name="TSource"/>  and <typeparamref name="TTarget"/>. 
        /// </summary>
        IAccessorInfoMatcher AccessorInfoMatcher { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="IValueConverter"/> that is responsible 
        /// for converting values between <typeparamref name="TSource"/>  and <typeparamref name="TTarget"/>
        /// </summary>
        IValueConverter ValueConverter { get; set; }

        /// <summary>
        /// Resets the <see cref="IMicroMapper{TSource,TTarget}"/> back to its initial state.
        /// </summary>
        void Reset();

        /// <summary>
        /// Gets an <see cref="IEnumerable{T}"/> that contains the matching accessors between 
        /// <typeparamref name="TSource"/> and <typeparamref name="TTarget"/>
        /// </summary>
        /// <remarks>
        /// This returns <b>null</b> before the first call to <see cref="Apply(TSource)"/> and 
        /// after a call to <see cref="Reset"/>.
        /// </remarks>
        IEnumerable<IAccessorInfoMatch> AccessorMatches { get; }

        /// <summary>
        /// Allows a <see cref="TTarget"/> to be processed after beeing mapped from <see cref="TSource"/>.
        /// </summary>
        Action<TTarget> TargetPostProcessor { get; set; }

    }

}
